﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;

namespace I_C
{
    class I2CLine
    {
        #region =================================== Internal data
        // ========== A font
        static Font aFont = new Font("Calibri", 10, FontStyle.Bold);
        static StringFormat center;
        static Rectangle drawRectangle;

        // ========== Data line
        PointF pointA;
        PointF pointB;
        PointF pointLast;

        float _y_high;
        float _y_low;
        float fraction;
        float pointLeft;
        Pen pen;

        float[] axeSpacing = { 0.5F, 2F };
        static Pen axePen;

        // ========== Offsets
        static float delta_X;
        static float half_delta_X;
        static float delta_Y;
        #endregion
        #region =================================== Constructor and propreties
        public I2CLine()
        {
            Fraction = 0.34f;
            Pen = Pens.LawnGreen;
            DELTA_X = 40;
            DELTA_Y = 40;

            if (axePen == null)
            {
                axePen = new Pen(Color.Gray, 0.5F);
                axePen.DashPattern = axeSpacing;
                axePen.DashStyle = DashStyle.DashDot;
            }

            center = new StringFormat();
            center.Alignment = StringAlignment.Center;
            center.LineAlignment = StringAlignment.Center;
            drawRectangle = new Rectangle();
        }
        public float Fraction
        {
            get
            {
                return fraction;
            }
            set
            {
                fraction = value;
            }
        }
        public Pen Pen
        {
            get
            {
                return pen;
            }
            set
            {
                pen = value;
            }
        }
        public float Y
        {
            get
            {
                return _y_low;
            }
            set
            {
                _y_low = value;
                _y_high = _y_low - delta_Y;
                pointLast.Y = _y_high;
            }
        }
        public static float DELTA_X
        {
            get
            {
                return delta_X;
            }
            set
            {
                delta_X = value;
                half_delta_X = value / 2;
            }
        }
        public static float DELTA_Y
        {
            get
            {
                return delta_Y;
            }
            set
            {
                delta_Y = value;
            }
        }
        public float PointLeft
        {
            get
            {
                return pointLeft;
            }
            set
            {
                pointLeft = value;
                pointLast.X = pointLeft;
                pointLast.Y = Y;
            }
        }
        public bool IsHigh
        {
            get
            {
                return pointLast.Y != _y_low;
            }
        }
        public bool IsLow
        {
            get
            {
                return !IsHigh;
            }
        }
        public PointF LastPoint
        {
            get
            {
                return pointLast;
            }
            set
            {
                pointLast = value;
            }
        }
        #endregion
        #region =================================== Draw Atomics
        // ============================================================================
        /// <summary> Draw SDA high to low </summary>
        // ============================================================================
        public void Draw_HighToLow(Graphics g)
        {
            pointLast.Y = _y_high;
            Draw_ToLow(g);
        }
        // ============================================================================
        /// <summary> Draw SDA Low to High </summary>
        // ============================================================================
        public void Draw_LowToHigh(Graphics g)
        {
            pointLast.Y = _y_low;
            Draw_ToHigh(g);
        }
        // ============================================================================
        /// <summary> Draw SDA High </summary>
        // ============================================================================
        public void Draw_High(Graphics g)
        {
            pointA.X = pointLeft;
            pointA.Y = _y_high;

            pointLeft += delta_X;
            pointB.X = pointLeft;
            pointB.Y = pointA.Y;

            g.DrawLine(pen, pointA, pointB);

            SavePosition();
        }
        // ============================================================================
        /// <summary> Draw SDA Low </summary>
        // ============================================================================
        public void Draw_Low(Graphics g)
        {
            pointA.X = pointLeft;
            pointA.Y = _y_low;

            pointLeft += delta_X;
            pointB.X = pointLeft;
            pointB.Y = pointA.Y;

            g.DrawLine(pen, pointA, pointB);

            SavePosition();
        }
        // ============================================================================
        /// <summary> Draw SDA towards low </summary>
        // ============================================================================
        public void Draw_ToLow(Graphics g)
        {
            // left
            pointA.X = pointLeft;
            pointA.Y = pointLast.Y;

            pointB.X = pointLeft + fraction * delta_X;
            pointB.Y = pointA.Y;

            g.DrawLine(pen, pointA, pointB);

            // middle
            pointA = pointB;

            pointB.X = pointLeft + (1 - fraction) * delta_X;
            pointB.Y = _y_low;

            g.DrawLine(pen, pointA, pointB);
            // right
            pointA = pointB;
            pointB.X = pointLeft + delta_X;

            g.DrawLine(pen, pointA, pointB);

            pointLeft += delta_X;

            SavePosition();
        }
        // ============================================================================
        /// <summary> Draw Sda towards high </summary>
        // ============================================================================
        public void Draw_ToHigh(Graphics g)
        {
            // left
            pointA.X = pointLeft;
            pointA.Y = pointLast.Y;

            pointB.X = pointLeft + fraction * delta_X;
            pointB.Y = pointA.Y;

            g.DrawLine(pen, pointA, pointB);

            // middle
            pointA = pointB;
            pointB.X = pointLeft + (1 - fraction) * delta_X;
            pointB.Y = _y_high;

            g.DrawLine(pen, pointA, pointB);
            // right
            pointA = pointB;
            pointB.X = pointLeft + delta_X;

            g.DrawLine(pen, pointA, pointB);

            pointLeft += delta_X;

            SavePosition();
        }
        // ============================================================================
        /// <summary> Draw Straigh to high </summary>
        // ============================================================================
        public void Draw_StraightToHigh(Graphics g)
        {
            pointLeft += fraction * delta_X;
            // middle
            pointA = pointLast;
            pointB.X = pointLeft;
            pointB.Y = _y_high;

            g.DrawLine(pen, pointA, pointB);

            SavePosition();
        }
        // ============================================================================
        /// <summary> Draw Straigh to low </summary>
        // ============================================================================
        public void Draw_StraightToLow(Graphics g)
        {
            pointLeft += fraction * delta_X;
            // middle
            pointA = pointLast;
            pointB.X = pointLeft;
            pointB.Y = _y_low;

            g.DrawLine(pen, pointA, pointB);

            SavePosition();
        }
        // ============================================================================
        /// <summary> Draw half of the last </summary>
        // ============================================================================
        public void Draw_HalfLast(Graphics g)
        {
            pointLeft += half_delta_X;

            pointA = pointLast;

            pointB.X = pointLeft;
            pointB.Y = pointA.Y;

            g.DrawLine(pen, pointA, pointB);

            SavePosition();
        }
        // ============================================================================
        /// <summary> Draw third of the last </summary>
        // ============================================================================
        public void Draw_ThirdLast(Graphics g)
        {
            pointLeft += fraction * DELTA_X;

            pointA = pointLast;

            pointB.X = pointLeft;
            pointB.Y = pointA.Y;

            g.DrawLine(pen, pointA, pointB);

            SavePosition();
        }
        // ============================================================================
        /// <summary> Draw two thirds of the last </summary>
        // ============================================================================
        public void Draw_TwoThirdsLast(Graphics g)
        {
            pointLeft += (1 - fraction) * DELTA_X;

            pointA = pointLast;

            pointB.X = pointLeft;
            pointB.Y = pointA.Y;

            g.DrawLine(pen, pointA, pointB);

            SavePosition();
        }
        // ============================================================================
        /// <summary> Draw an entire Clock </summary>
        // ============================================================================
        public void Draw_Clock(Graphics g)
        {
            Draw_ToHigh(g);
            Draw_ToLow(g);
        }
        // ============================================================================
        /// <summary> Draw last </summary>
        // ============================================================================
        public void Draw_Last(Graphics g)
        {
            pointLeft += delta_X;

            pointA = pointLast;

            pointB.X = pointLeft;
            pointB.Y = pointA.Y;

            g.DrawLine(pen, pointA, pointB);

            SavePosition();
        }
        // ============================================================================
        /// <summary> Draw information </summary>
        // ============================================================================
        public static void DrawInformation(Graphics g, Brush brush, String info, PointF startPoint, float width)
        {
            drawRectangle.X = (int) startPoint.X;
            drawRectangle.Y = (int) startPoint.Y;
            drawRectangle.Width = (int) width;
            drawRectangle.Height = (int) aFont.Size * 2;

            g.DrawString(info, aFont, brush, drawRectangle, center);
        }
        // ============================================================================
        /// <summary> Draw a vertical axe </summary>
        // ============================================================================
        public static void DrawVerticalAxe(Graphics g, float X, float Height)
        {
            g.DrawLine(axePen, X, 0, X, Height);
        }
        // ============================================================================
        /// <summary> Draw a small delimiter vertical line </summary>
        // ============================================================================
        public void DrawDelimiter(Graphics g)
        {
            g.DrawLine(axePen, pointLast.X, _y_high - delta_Y, pointLast.X, _y_low);
        }
        #endregion
        #region =================================== Draw Utils
        public void SavePosition()
        {
            // ========== Save the last position of SDA
            pointLast = pointB;
        }
        #endregion
    }
}
